#include <ani.h>
#include <array>
#include <iostream>
#include <vector>

static ani_string handleData_Class(ani_env *env, [[maybe_unused]] ani_object obj)
{
    std::string s = "come from class";
    ani_string result;
    env->String_NewUTF8(s.c_str(), s.size(), &result);
    return result;
}

static ani_string handleData_NS(ani_env *env)
{
    std::string s = "come from class";
    ani_string result;
    env->String_NewUTF8(s.c_str(), s.size(), &result);
    return result;
}

ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
{
    ani_env *env;

    if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env))
    {
        std::cerr << "Unsupported ANI_VERSION_1" << std::endl;
        return ANI_ERROR;
    }
    {
        static const char *className = "ani_async_wrapper.ClassMode";

        ani_class cls;
        if (ANI_OK != env->FindClass(className, &cls))
        {
            std::cerr << "Not found '" << className << "'" << std::endl;
            return ANI_ERROR;
        }
    
        std::array methods = {
            ani_native_function{"getString", ":C{std.core.String}", reinterpret_cast<void *>(handleData_Class)},
        };
    
        std::cout << "Start bind native methods to '" << className << "'" << std::endl;
    
        if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size()))
        {
            std::cerr << "Cannot bind native methods to '" << className << "'" << std::endl;
            return ANI_ERROR;
        };
        std::cout << "Finish bind native methods to '" << className << "'" << std::endl;
    }
    {
        static const char *namespaceName = "ani_async_wrapper.NsMode";
        ani_namespace ns;
        if (ANI_OK != env->FindNamespace(namespaceName, &ns))
        {
            std::cerr << "Not found '" << namespaceName << "'" << std::endl;
            return ANI_ERROR;
        }
        std::array methods = {
            ani_native_function{"getString", ":C{std.core.String}", reinterpret_cast<void *>(handleData_NS)},
        };
        std::cout << "Start bind native methods to '" << namespaceName << "'" << std::endl;
    
        if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size()))
        {
            std::cerr << "Cannot bind native methods to '" << namespaceName << "'" << std::endl;
            return ANI_ERROR;
        };
        std::cout << "Finish bind native methods to '" << namespaceName << "'" << std::endl;
    }

    *result = ANI_VERSION_1;
    return ANI_OK;
}